/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skyproc;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;
import java.util.zip.DataFormatException;
import lev.LExporter;
import lev.LFlags;
import lev.LStream;
import skyproc.exceptions.BadParameter;
import skyproc.exceptions.BadRecord;

/**
 *
 * @author Justin Swanson
 */
public class ENCH extends MagicItem {

    ENIT ENIT = new ENIT();
    static Type[] types = {Type.ENCH};

    ENCH() {
	super();
	init();

	subRecords.add(OBND);
	subRecords.add(FULL);
	subRecords.add(ENIT);
	subRecords.add(magicEffects);
	subRecords.add(keywords);
    }

    @Override
    Type[] getTypes() {
	return types;
    }

    @Override
    Record getNew() {
	return new ENCH();
    }

    class ENIT extends SubRecord {

	int baseCost = 0;
	LFlags flags = new LFlags(4);
	CastType castType = CastType.ConstantEffect;
	int chargeAmount = 0;
	DeliveryType targetType = DeliveryType.Self;
	EnchantType enchantType = EnchantType.Enchantment;
	float chargeTime = 0;
	FormID baseEnchantment = new FormID();
	FormID wornRestrictions = new FormID();

	ENIT() {
	    super(Type.ENIT);
	}

	@Override
	void export(LExporter out, Mod srcMod) throws IOException {
	    super.export(out, srcMod);
	    out.write(baseCost, 4);
	    out.write(flags.export());
	    out.write(castType.ordinal(), 4);
	    out.write(chargeAmount, 4);
	    out.write(targetType.ordinal(), 4);
	    out.write(enchantType.value, 4);
	    out.write(chargeTime);
	    baseEnchantment.export(out);
	    wornRestrictions.export(out);
	}

	@Override
	void parseData(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	    super.parseData(in);
	    baseCost = in.extractInt(4);
	    flags.set(in.extract(4));
	    castType = CastType.values()[in.extractInt(4)];
	    chargeAmount = in.extractInt(4);
	    targetType = DeliveryType.values()[in.extractInt(4)];
	    enchantType = EnchantType.value(in.extractInt(4));
	    chargeTime = in.extractFloat();
	    baseEnchantment.setInternal(in.extract(4));
	    wornRestrictions.setInternal(in.extract(4));
	}

	@Override
	SubRecord getNew(Type type) {
	    return new ENIT();
	}

	@Override
	int getContentLength(Mod srcMod) {
	    return 36;
	}

	@Override
	ArrayList<FormID> allFormIDs() {
	    ArrayList<FormID> out = new ArrayList<FormID>(2);
	    out.add(baseEnchantment);
	    out.add(wornRestrictions);
	    return out;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final ENIT other = (ENIT) obj;
            if (this.baseCost != other.baseCost) {
                return false;
            }
            if (!Objects.equals(this.flags, other.flags)) {
                return false;
            }
            if (this.castType != other.castType) {
                return false;
            }
            if (this.chargeAmount != other.chargeAmount) {
                return false;
            }
            if (this.targetType != other.targetType) {
                return false;
            }
            if (this.enchantType != other.enchantType) {
                return false;
            }
            if (Float.floatToIntBits(this.chargeTime) != Float.floatToIntBits(other.chargeTime)) {
                return false;
            }
            if (!Objects.equals(this.baseEnchantment, other.baseEnchantment)) {
                return false;
            }
            if (!Objects.equals(this.wornRestrictions, other.wornRestrictions)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 79 * hash + this.baseCost;
            hash = 79 * hash + Objects.hashCode(this.flags);
            hash = 79 * hash + (this.castType != null ? this.castType.hashCode() : 0);
            hash = 79 * hash + this.chargeAmount;
            hash = 79 * hash + (this.targetType != null ? this.targetType.hashCode() : 0);
            hash = 79 * hash + (this.enchantType != null ? this.enchantType.hashCode() : 0);
            hash = 79 * hash + Float.floatToIntBits(this.chargeTime);
            hash = 79 * hash + Objects.hashCode(this.baseEnchantment);
            hash = 79 * hash + Objects.hashCode(this.wornRestrictions);
            return hash;
        }
        
        @Override
        public SubRecord merge(SubRecord no, SubRecord bo) {
            ENIT e = this;
            if (!(no == null && bo == null && (no instanceof ENIT) && (bo instanceof ENIT))) {
                final ENIT ne = (ENIT) no;
                final ENIT be = (ENIT) bo;
                SkyBash.merge(e.baseCost, ne.baseCost, be.baseCost, type[0], "base cost");
                e.flags.merge(ne.flags, be.flags, type[0]);
                SkyBash.merge(e.castType, ne.castType, be.castType, type[0], "cast type");
                e.baseEnchantment.merge(ne.baseEnchantment, be.baseEnchantment, type[0]);
                e.wornRestrictions.merge(ne.wornRestrictions, be.wornRestrictions, type[0]);
                SkyBash.merge(e.chargeAmount, ne.chargeAmount, be.chargeAmount, type[0], "charge amount");
                SkyBash.merge(e.targetType, ne.targetType, be.targetType, type[0], "target type");
                SkyBash.merge(e.enchantType, ne.enchantType, be.enchantType, type[0], "enchant type");
                SkyBash.merge(e.chargeTime, ne.chargeTime, be.chargeTime, type[0], "charge time");
            }
            return e;
        }
    }
    
    /*
     * SkyBash functions.
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ENCH other = (ENCH) obj;
        if (!Objects.equals(this.ENIT, other.ENIT)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 79 * hash + Objects.hashCode(this.ENIT);
        return hash;
    }
    
    @Override
    public MajorRecord merge(MajorRecord no, MajorRecord bo) {
        super.merge(no, bo);
        ENCH e = this;
        if (!(no == null && bo == null && (no instanceof ENCH) && (bo instanceof ENCH))) {
            final ENCH ne = (ENCH) no;
            final ENCH be = (ENCH) bo;
            SubRecords sList = e.subRecords;
            SubRecords nsList = ne.subRecords;
            SubRecords bsList = be.subRecords;
            for (SubRecord s : sList) {
                s.merge(nsList.get(s.type[0]), bsList.get(s.type[0]));
            }
        }
        return e;
    }

    /**
     *
     */
    public enum EnchantType {

	/**
	 *
	 */
	Enchantment(6),
	/**
	 *
	 */
	StaffEnchantment(12);
	int value;

	EnchantType(int value) {
	    this.value = value;
	}

	static EnchantType value(int in) {
	    switch (in) {
		case 12:
		    return StaffEnchantment;
		default:
		    return Enchantment;
	    }
	}
    }

    /**
     *
     */
    public enum ENCHFlag {

	/**
	 *
	 */
	ManualCalc(0),
	/**
	 *
	 */
	ExtendDurationOnRecast(3);
	int value;

	ENCHFlag(int in) {
	    value = in;
	}
    }

    /**
     *
     * @param cost
     */
    public void setBaseCost(int cost) {
	ENIT.baseCost = cost;
    }

    /**
     *
     * @return
     */
    public int getBaseCost() {
	return ENIT.baseCost;
    }

    /**
     *
     * @param in
     * @param on
     */
    public void set(ENCHFlag in, boolean on) {
	ENIT.flags.set(in.value, on);
    }

    /**
     *
     * @param in
     * @return
     */
    public boolean get(ENCHFlag in) {
	return ENIT.flags.get(in.value);
    }

    /**
     *
     * @param type
     */
    public void setCastType(CastType type) {
	ENIT.castType = type;
    }

    /**
     *
     * @return
     */
    public CastType getCastType() {
	return ENIT.castType;
    }

    /**
     *
     * @param amount
     */
    public void setChargeAmount(int amount) {
	ENIT.chargeAmount = amount;
    }

    /**
     *
     * @return
     */
    public int getChargeAmount() {
	return ENIT.chargeAmount;
    }

    /**
     *
     * @param type
     */
    public void setDeliveryType(DeliveryType type) {
	ENIT.targetType = type;
    }

    /**
     *
     * @return
     */
    public DeliveryType getDeliveryType() {
	return ENIT.targetType;
    }

    /**
     *
     * @param type
     */
    public void setEnchantType(EnchantType type) {
	ENIT.enchantType = type;
    }

    /**
     *
     * @return
     */
    public EnchantType getEnchantType() {
	return ENIT.enchantType;
    }

    /**
     *
     * @param time
     */
    public void setChargeTime(float time) {
	ENIT.chargeTime = time;
    }

    /**
     *
     * @return
     */
    public float getChargeTime() {
	return ENIT.chargeTime;
    }

    /**
     *
     * @param id
     */
    public void setBaseEnchantment(FormID id) {
	ENIT.baseEnchantment = id;
    }

    /**
     *
     * @return
     */
    public FormID getBaseEnchantment() {
	return ENIT.baseEnchantment;
    }

    /**
     *
     * @param id
     */
    public void setWornRestrictions(FormID id) {
	ENIT.wornRestrictions = id;
    }

    /**
     *
     * @return
     */
    public FormID getWornRestrictions() {
	return ENIT.wornRestrictions;
    }
}
